package http

import (
	"geekbang-go-homework/week04/pkg/middleware"
	"net"
	"net/http"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc/grpclog"
)

// Server is a http server wrapper.
type Server struct {
	*http.Server
	network    string
	address    string
	timeout    time.Duration
	log        grpclog.LoggerV2
	handler    http.Handler
	middleware middleware.HandlerChain
}

func (s *Server) Start(ctx context.Context) error {
	lis, err := net.Listen(s.network, s.address)
	if err != nil {
		return err
	}
	s.log.Infof("[HTTP] server listening on: %s", lis.Addr().String())
	return s.Serve(lis)
}

func (s *Server) Stop(ctx context.Context) error {
	s.log.Info("[HTTP] server stopping")
	return s.Shutdown(ctx)
}

func NewServer(opts ...ServerOption) *Server {
	srv := &Server{
		network: "tcp",
		address: ":0",
		timeout: time.Second * 3,
	}
	for _, o := range opts {
		o(srv)
	}
	srv.Server = &http.Server{
		Handler: handler(srv)(srv.handler),
	}
	return srv
}

func handler(srv *Server) middleware.HandlerFunc {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
			var ctx context.Context
			var cancel context.CancelFunc
			if srv.timeout > 0 {
				ctx, cancel = context.WithTimeout(request.Context(), srv.timeout)
			} else {
				ctx, cancel = context.WithCancel(request.Context())
			}
			defer cancel()
			if len(srv.middleware) > 0 {
				next = srv.middleware.Chain()(next)
			}
			next.ServeHTTP(writer, request.WithContext(ctx))
		})
	}
}
